{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sZVlYSmRjzuk"
      },
      "source": [
        "# Tutorial: Classifying Documents & Queries by Language\n",
        "\n",
        "- **Level**: Beginner\n",
        "- **Time to complete**: 15 minutes\n",
        "- **Components Used**: [`InMemoryDocumentStore`](https://docs.haystack.deepset.ai/v2.0/docs/inmemorydocumentstore), [`DocumentLanguageClassifier`](https://docs.haystack.deepset.ai/v2.0/docs/documentlanguageclassifier), [`MetadataRouter`](https://docs.haystack.deepset.ai/v2.0/docs/metadatarouter), [`DocumentWriter`](https://docs.haystack.deepset.ai/v2.0/docs/documentwriter), [`TextLanguageRouter`](https://docs.haystack.deepset.ai/v2.0/docs/textlanguagerouter), [`DocumentJoiner`](https://docs.haystack.deepset.ai/v2.0/docs/documentjoiner), [`InMemoryBM25Retriever`](https://docs.haystack.deepset.ai/v2.0/docs/inmemorybm25retriever), [`PromptBuilder`](https://docs.haystack.deepset.ai/v2.0/docs/promptbuilder), [`OpenAIGenerator`](https://docs.haystack.deepset.ai/v2.0/docs/openaigenerator)\n",
        "- **Goal**: After completing this tutorial, you'll have learned how to build a Haystack pipeline to classify documents based on the (human) language they were written in.\n",
        "- Optionally, at the end you'll also incorporate language clasification and query routing into a RAG pipeline, so you can query documents based on the language a question was written in.\n",
        "\n",
        "> This tutorial uses Haystack 2.0 Beta. To learn more, read the [ Haystack 2.0 Beta announcement](https://haystack.deepset.ai/blog/introducing-haystack-2-beta-and-advent) or see [Haystack 2.0 Documentation](https://docs.haystack.deepset.ai/v2.0/docs).\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "G8qw1k7nf7yH"
      },
      "source": [
        "## Overview\n",
        "\n",
        "In a gobalized society with over 7,000 human languages spoken worldwide today, handling multilingual input is a common use case for NLP applications.\n",
        "\n",
        "Good news: Haystack has a [`DocumentLanguageClassifier`](https://docs.haystack.deepset.ai/v2.0/docs/documentlanguageclassifier) built in. This component detects the language a document was written in. This functionality lets you create *branches* in your Haystack pipelines, granting the flexibility to add different processing steps for each language. For example, you could use a LLM that performs better in German to answer German queries. Or, you could fetch only French restaurant reviews for your French users.\n",
        "\n",
        "In this tutorial, you'll take a text samples from hotel reviews, written in different languages. The text samples will be made into Haystack documents and classified by language. Then each document will be written to a language-specific `DocumentStore`. To validate that the language detection is working correctly, you'll filter the document stores to display their contents.\n",
        "\n",
        "In the last section, you'll build a multi-lingual RAG pipeline. The language of a question is detected, and only documents in that language are used to generate the answer. For this section, the [`TextLanguageRouter`](https://docs.haystack.deepset.ai/v2.0/docs/textlanguagerouter) will come in handy.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oBa4Q25cGTr6"
      },
      "source": [
        "## Preparing the Colab Environment\n",
        "\n",
        "- [Enable GPU Runtime in Colab](https://docs.haystack.deepset.ai/docs/enabling-gpu-acceleration#enabling-the-gpu-in-colab)\n",
        "- [Set logging level to INFO](https://docs.haystack.deepset.ai/docs/log-level)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oC7ff5x0XTfN"
      },
      "source": [
        "# Installing Haystack\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "lxgAfuxcdftS",
        "outputId": "36339d6b-f7a8-4686-911a-60642a8adbe6"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Requirement already satisfied: haystack-ai in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (2.0.0b6)\n",
            "Requirement already satisfied: boilerpy3 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (1.0.7)\n",
            "Requirement already satisfied: haystack-bm25 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (1.0.2)\n",
            "Requirement already satisfied: jinja2 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (3.1.3)\n",
            "Requirement already satisfied: lazy-imports in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (0.3.1)\n",
            "Requirement already satisfied: more-itertools in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (10.2.0)\n",
            "Requirement already satisfied: networkx in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (3.2.1)\n",
            "Requirement already satisfied: openai>=1.1.0 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (1.10.0)\n",
            "Requirement already satisfied: pandas in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (2.2.0)\n",
            "Requirement already satisfied: posthog in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (3.3.4)\n",
            "Requirement already satisfied: pyyaml in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (6.0.1)\n",
            "Requirement already satisfied: tenacity in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (8.2.3)\n",
            "Requirement already satisfied: tqdm in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (4.66.1)\n",
            "Requirement already satisfied: typing-extensions in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (4.9.0)\n",
            "Requirement already satisfied: anyio<5,>=3.5.0 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from openai>=1.1.0->haystack-ai) (4.2.0)\n",
            "Requirement already satisfied: distro<2,>=1.7.0 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from openai>=1.1.0->haystack-ai) (1.9.0)\n",
            "Requirement already satisfied: httpx<1,>=0.23.0 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from openai>=1.1.0->haystack-ai) (0.26.0)\n",
            "Requirement already satisfied: pydantic<3,>=1.9.0 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from openai>=1.1.0->haystack-ai) (2.6.0)\n",
            "Requirement already satisfied: sniffio in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from openai>=1.1.0->haystack-ai) (1.3.0)\n",
            "Requirement already satisfied: numpy in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-bm25->haystack-ai) (1.26.3)\n",
            "Requirement already satisfied: MarkupSafe>=2.0 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from jinja2->haystack-ai) (2.1.4)\n",
            "Requirement already satisfied: python-dateutil>=2.8.2 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from pandas->haystack-ai) (2.8.2)\n",
            "Requirement already satisfied: pytz>=2020.1 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from pandas->haystack-ai) (2023.4)\n",
            "Requirement already satisfied: tzdata>=2022.7 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from pandas->haystack-ai) (2023.4)\n",
            "Requirement already satisfied: requests<3.0,>=2.7 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from posthog->haystack-ai) (2.31.0)\n",
            "Requirement already satisfied: six>=1.5 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from posthog->haystack-ai) (1.16.0)\n",
            "Requirement already satisfied: monotonic>=1.5 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from posthog->haystack-ai) (1.6)\n",
            "Requirement already satisfied: backoff>=1.10.0 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from posthog->haystack-ai) (2.2.1)\n",
            "Requirement already satisfied: idna>=2.8 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from anyio<5,>=3.5.0->openai>=1.1.0->haystack-ai) (3.6)\n",
            "Requirement already satisfied: certifi in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from httpx<1,>=0.23.0->openai>=1.1.0->haystack-ai) (2023.11.17)\n",
            "Requirement already satisfied: httpcore==1.* in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from httpx<1,>=0.23.0->openai>=1.1.0->haystack-ai) (1.0.2)\n",
            "Requirement already satisfied: h11<0.15,>=0.13 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from httpcore==1.*->httpx<1,>=0.23.0->openai>=1.1.0->haystack-ai) (0.14.0)\n",
            "Requirement already satisfied: annotated-types>=0.4.0 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from pydantic<3,>=1.9.0->openai>=1.1.0->haystack-ai) (0.6.0)\n",
            "Requirement already satisfied: pydantic-core==2.16.1 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from pydantic<3,>=1.9.0->openai>=1.1.0->haystack-ai) (2.16.1)\n",
            "Requirement already satisfied: charset-normalizer<4,>=2 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from requests<3.0,>=2.7->posthog->haystack-ai) (3.3.2)\n",
            "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from requests<3.0,>=2.7->posthog->haystack-ai) (2.2.0)\n",
            "Collecting langdetect\n",
            "  Downloading langdetect-1.0.9.tar.gz (981 kB)\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m981.5/981.5 kB\u001b[0m \u001b[31m11.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
            "\u001b[?25h  Preparing metadata (setup.py): started\n",
            "  Preparing metadata (setup.py): finished with status 'done'\n",
            "Requirement already satisfied: six in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from langdetect) (1.16.0)\n",
            "Building wheels for collected packages: langdetect\n",
            "  Building wheel for langdetect (setup.py): started\n",
            "  Building wheel for langdetect (setup.py): finished with status 'done'\n",
            "  Created wheel for langdetect: filename=langdetect-1.0.9-py3-none-any.whl size=993224 sha256=8ec8e722a5a05de5f2df58f42eeb655dad2d4dce611f88b04c375fd435f3f36a\n",
            "  Stored in directory: /Users/tuanacelik/Library/Caches/pip/wheels/c1/67/88/e844b5b022812e15a52e4eaa38a1e709e99f06f6639d7e3ba7\n",
            "Successfully built langdetect\n",
            "Installing collected packages: langdetect\n",
            "Successfully installed langdetect-1.0.9\n"
          ]
        }
      ],
      "source": [
        "%%bash\n",
        "\n",
        "pip install haystack-ai\n",
        "pip install langdetect"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "32oB-HJlGXmY"
      },
      "source": [
        "### Enabling Telemetry\n",
        "\n",
        "Knowing you're using this tutorial helps us decide where to invest our efforts to build a better product but you can always opt out by commenting the following line. See [Telemetry](https://docs.haystack.deepset.ai/v2.0/docs/enabling-telemetry) for more details."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "id": "Ubr7yVt6Gbnj"
      },
      "outputs": [],
      "source": [
        "from haystack.telemetry import tutorial_running\n",
        "\n",
        "tutorial_running(32)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "K0wRwkyvkV3Z"
      },
      "source": [
        "## Write Documents Into `InMemoryDocumentStore`\n",
        "\n",
        "The following indexing pipeline writes French and English documents into their own `InMemoryDocumentStores` based on language.\n",
        "\n",
        "Import the modules you'll need. Then instantiate a list of Haystack `Documents` that are snippets of hotel reviews in various languages."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "id": "mN2fFuWWP_8D"
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "/Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
            "  from .autonotebook import tqdm as notebook_tqdm\n"
          ]
        }
      ],
      "source": [
        "from haystack import Document, Pipeline\n",
        "from haystack.document_stores.in_memory import InMemoryDocumentStore\n",
        "from haystack.components.classifiers import DocumentLanguageClassifier\n",
        "from haystack.components.routers import MetadataRouter\n",
        "from haystack.components.writers import DocumentWriter\n",
        "\n",
        "\n",
        "documents = [\n",
        "             Document(content = \"Super appartement. Juste au dessus de plusieurs bars qui ferment très tard. A savoir à l'avance. (Bouchons d'oreilles fournis !)\"),\n",
        "             Document(content = \"El apartamento estaba genial y muy céntrico, todo a mano. Al lado de la librería Lello y De la Torre de los clérigos. Está situado en una zona de marcha, así que si vais en fin de semana , habrá ruido, aunque a nosotros no nos molestaba para dormir\"),\n",
        "             Document(content = \"The keypad with a code is convenient and the location is convenient. Basically everything else, very noisy, wi-fi didn't work, check-in person didn't explain anything about facilities, shower head was broken, there's no cleaning and everything else one may need is charged.\"),\n",
        "             Document(content = \"It is very central and appartement has a nice appearance (even though a lot IKEA stuff), *W A R N I N G** the appartement presents itself as a elegant and as a place to relax, very wrong place to relax - you cannot sleep in this appartement, even the beds are vibrating from the bass of the clubs in the same building - you get ear plugs from the hotel -> now I understand why -> I missed a trip as it was so loud and I could not hear the alarm next day due to the ear plugs.- there is a green light indicating 'emergency exit' just above the bed, which shines very bright at night - during the arrival process, you felt the urge of the agent to leave as soon as possible. - try to go to 'RVA clerigos appartements' -> same price, super quiet, beautiful, city center and very nice staff (not an agency)- you are basically sleeping next to the fridge, which makes a lot of noise, when the compressor is running -> had to switch it off - but then had no cool food and drinks. - the bed was somehow broken down - the wooden part behind the bed was almost falling appart and some hooks were broken before- when the neighbour room is cooking you hear the fan very loud. I initially thought that I somehow activated the kitchen fan\"),\n",
        "             Document(content = \"Un peu salé surtout le sol. Manque de service et de souplesse\"),\n",
        "             Document(content = \"Nous avons passé un séjour formidable. Merci aux personnes , le bonjours à Ricardo notre taxi man, très sympathique. Je pense refaire un séjour parmi vous, après le confinement, tout était parfait, surtout leur gentillesse, aucune chaude négative. Je n'ai rien à redire de négative, Ils étaient a notre écoute, un gentil message tout les matins, pour nous demander si nous avions besoins de renseignement et savoir si tout allait bien pendant notre séjour.\"),\n",
        "             Document(content = \"Céntrico. Muy cómodo para moverse y ver Oporto. Edificio con terraza propia en la última planta. Todo reformado y nuevo. Te traen un estupendo desayuno todas las mañanas al apartamento. Solo que se puede escuchar algo de ruido de la calle a primeras horas de la noche. Es un zona de ocio nocturno. Pero respetan los horarios.\")]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "TcZbAvjbRJLA"
      },
      "source": [
        "Each language gets its own `DocumentStore`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "metadata": {
        "id": "rfC1ZCigQJgI"
      },
      "outputs": [],
      "source": [
        "en_document_store = InMemoryDocumentStore()\n",
        "fr_document_store = InMemoryDocumentStore()\n",
        "es_document_store = InMemoryDocumentStore()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "d9fyP-ThRTue"
      },
      "source": [
        "The `DocumentLanguageClassifier` takes a list of languages. The `MetadataRouter` needs a dictionary of rules.  These rules specify which node to route a document to (in this case, which language-specific `DocumentWriter`), based on the document's metadata.\n",
        "\n",
        "The keys of the dictionary are the names of the output connections, and the values are dictionaries that follow the format of [filtering expressions in Haystack.](https://docs.haystack.deepset.ai/v2.0/docs/metadata-filtering).\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "metadata": {
        "id": "FlqGdbuxQNKk"
      },
      "outputs": [],
      "source": [
        "\n",
        "language_classifier = DocumentLanguageClassifier(languages = [\"en\", \"fr\", \"es\"])\n",
        "router_rules = {\"en\": {\"language\": {\"$eq\": \"en\"}},\n",
        "                \"fr\": {\"language\": {\"$eq\": \"fr\"}},\n",
        "                \"es\": {\"language\": {\"$eq\": \"es\"}}}\n",
        "router = MetadataRouter(rules=router_rules)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "metadata": {
        "id": "FEw5pfmBQRBB"
      },
      "outputs": [],
      "source": [
        "en_writer = DocumentWriter(document_store = en_document_store)\n",
        "fr_writer = DocumentWriter(document_store = fr_document_store)\n",
        "es_writer = DocumentWriter(document_store = es_document_store)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kAQvRdtESq_J"
      },
      "source": [
        "Now that all the components have been created, instantiate the `Pipeline`. Add the components to the pipeline. Connect the outputs of one component to the input of the following component."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "metadata": {
        "id": "BdvO_fEfcVAY"
      },
      "outputs": [],
      "source": [
        "\n",
        "indexing_pipeline = Pipeline()\n",
        "indexing_pipeline.add_component(instance=language_classifier, name=\"language_classifier\")\n",
        "indexing_pipeline.add_component(instance=router, name=\"router\")\n",
        "indexing_pipeline.add_component(instance=en_writer, name=\"en_writer\")\n",
        "indexing_pipeline.add_component(instance=fr_writer, name=\"fr_writer\")\n",
        "indexing_pipeline.add_component(instance=es_writer, name=\"es_writer\")\n",
        "\n",
        "\n",
        "indexing_pipeline.connect(\"language_classifier\", \"router\")\n",
        "indexing_pipeline.connect(\"router.en\", \"en_writer\")\n",
        "indexing_pipeline.connect(\"router.fr\", \"fr_writer\")\n",
        "indexing_pipeline.connect(\"router.es\", \"es_writer\")\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ulAiCB1vTIbr"
      },
      "source": [
        "Draw a diagram of the pipeline to see what the graph looks like."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "metadata": {
        "id": "598ZTa7RzNeR"
      },
      "outputs": [],
      "source": [
        "indexing_pipeline.draw('indexing_pipeline.png')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UzQX7zFLS_Bk"
      },
      "source": [
        "Run the pipeline and it will tell you how many documents were written in each language. Voila!"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "lE5XE8cPXN5-",
        "outputId": "43017d9b-65f8-48ad-dadb-66ad0de3af43"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'router': {'unmatched': []},\n",
              " 'en_writer': {'documents_written': 2},\n",
              " 'fr_writer': {'documents_written': 3},\n",
              " 'es_writer': {'documents_written': 2}}"
            ]
          },
          "execution_count": 13,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "indexing_pipeline.run(data={\"language_classifier\": {\"documents\": documents}})"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "R-Q2SxDnu3v-"
      },
      "source": [
        "### Check the Contents of Your Document Stores\n",
        "\n",
        "You can check the contents of your document stores. Each one should only contain documents in the correct language."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "LNHzxz52uxZV",
        "outputId": "d0459677-73c0-4bb6-f5d3-87c0c00b1552"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "English documents:  [Document(id=8f64ab234c6a5d5652d02bed144d069ec6e988903b071d16fffbf400abfc1047, content: 'The keypad with a code is convenient and the location is convenient. Basically everything else, very...', meta: {'language': 'en'}), Document(id=d4d878288efba5e28a43ae0195e43dadd0298fe36d3d9b3075c5c5120d27763e, content: 'It is very central and appartement has a nice appearance (even though a lot IKEA stuff), *W A R N I ...', meta: {'language': 'en'})]\n",
            "French documents:  [Document(id=ea7ea338874232de2d8105a258813f50345db82772e21ad2c4549dbb7adce8a3, content: 'Super appartement. Juste au dessus de plusieurs bars qui ferment très tard. A savoir à l'avance. (Bo...', meta: {'language': 'fr'}), Document(id=6b64c8a60543ee32b81cd39bc8d6e09fae4bff1b22c6ccdcf414db26fa354e7a, content: 'Un peu salé surtout le sol. Manque de service et de souplesse', meta: {'language': 'fr'}), Document(id=b1be23526f19a8af80a190e775bfd05e65878e585529037cb45b47267a4eaa98, content: 'Nous avons passé un séjour formidable. Merci aux personnes , le bonjours à Ricardo notre taxi man, t...', meta: {'language': 'fr'})]\n",
            "Spanish documents:  [Document(id=72b094c163b22a660528bc5adbdf0fecf96b4b4d753c1b117f15dba482d2f948, content: 'El apartamento estaba genial y muy céntrico, todo a mano. Al lado de la librería Lello y De la Torre...', meta: {'language': 'es'}), Document(id=4b37b8bdfffccfb3211ea167b4fdc5121ca51fc5f869b4f834e8da473f0d3353, content: 'Céntrico. Muy cómodo para moverse y ver Oporto. Edificio con terraza propia en la última planta. Tod...', meta: {'language': 'es'})]\n"
          ]
        }
      ],
      "source": [
        "print(\"English documents: \", en_document_store.filter_documents())\n",
        "print(\"French documents: \", fr_document_store.filter_documents())\n",
        "print(\"Spanish documents: \", es_document_store.filter_documents())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "A6J0ac9UWdrT"
      },
      "source": [
        "## (Optional) Create a Multi-Lingual RAG pipeline\n",
        "\n",
        "To build a multi-lingual RAG pipeline, you can use the[`TextLanguageRouter`](https://docs.haystack.deepset.ai/v2.0/docs/textlanguagerouter) to detect the language of the query. Then, fetch documents in that same language from the correct `DocumentStore`.\n",
        "\n",
        "In order to do this you'll need an [OpenAI access token](https://help.openai.com/en/articles/4936850-where-do-i-find-my-api-key), although this approach would also work with any other [generator Haystack supports](https://docs.haystack.deepset.ai/v2.0/docs/generators)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "hVJaARodWezy",
        "outputId": "d9bdcb42-bd50-4fd9-f4d8-a69e8b4b64f8"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "from getpass import getpass\n",
        "\n",
        "os.environ[\"OPENAI_API_KEY\"] = getpass(\"Enter OpenAI API key:\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ei8up-k3qOC4"
      },
      "source": [
        "Let's assume that all these reviews we put in our document stores earlier are for the same accommodation. A RAG pipeline will let you query for information about that apartment, in the language you choose.\n",
        "\n",
        "Import the components you'll need for a RAG pipeline. Write a prompt that will be passed to our LLM, along with the relevant documents."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "metadata": {
        "id": "CN1N2sn1yUVx"
      },
      "outputs": [],
      "source": [
        "from haystack.components.retrievers.in_memory import InMemoryBM25Retriever\n",
        "from haystack.components.joiners import DocumentJoiner\n",
        "from haystack.components.builders import PromptBuilder\n",
        "from haystack.components.generators import OpenAIGenerator\n",
        "from haystack.components.routers import TextLanguageRouter\n",
        "\n",
        "prompt_template = \"\"\"\n",
        "You will be provided with reviews for an accommodation.\n",
        "Answer the question concisely based solely on the given reviews.\n",
        "Reviews:\n",
        "  {% for doc in documents %}\n",
        "    {{ doc.content }}\n",
        "  {% endfor %}\n",
        "Question: {{ query}}\n",
        "Answer:\n",
        "\"\"\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WTCT6u4cz_z6"
      },
      "source": [
        "### Build the Pipeline\n",
        "\n",
        "Create a new `Pipeline`. Add the following components:\n",
        "- `TextLanguageRouter`\n",
        "- `InMemoryBM25Retriever`. You'll need a retriever per language, since each language has its own `DocumentStore`.\n",
        "- `DocumentJoiner`\n",
        "- `PromptBuilder`\n",
        "- `OpenAIGenerator`\n",
        "\n",
        "> Note: The `BM25Retriever` essentially does keyword matching, which isn't as accurate as other search methods. In order to make the LLM responses more precise, you could refacctor your piplines to use an [`EmbeddingRetriever`](https://docs.haystack.deepset.ai/v2.0/docs/inmemoryembeddingretriever) which performs vector search over the documents."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "metadata": {
        "id": "BN1Hr_BjWKcl"
      },
      "outputs": [],
      "source": [
        "\n",
        "rag_pipeline = Pipeline()\n",
        "rag_pipeline.add_component(instance=TextLanguageRouter(['en', 'fr', 'es']), name=\"router\")\n",
        "rag_pipeline.add_component(instance=InMemoryBM25Retriever(document_store=en_document_store), name=\"en_retriever\")\n",
        "rag_pipeline.add_component(instance=InMemoryBM25Retriever(document_store=fr_document_store), name=\"fr_retriever\")\n",
        "rag_pipeline.add_component(instance=InMemoryBM25Retriever(document_store=es_document_store), name=\"es_retriever\")\n",
        "rag_pipeline.add_component(instance=DocumentJoiner(), name=\"joiner\")\n",
        "rag_pipeline.add_component(instance=PromptBuilder(template=prompt_template), name=\"prompt_builder\")\n",
        "rag_pipeline.add_component(instance=OpenAIGenerator(), name=\"llm\")\n",
        "\n",
        "\n",
        "rag_pipeline.connect(\"router.en\", \"en_retriever.query\")\n",
        "rag_pipeline.connect(\"router.fr\", \"fr_retriever.query\")\n",
        "rag_pipeline.connect(\"router.es\", \"es_retriever.query\")\n",
        "rag_pipeline.connect(\"en_retriever\", \"joiner\")\n",
        "rag_pipeline.connect(\"fr_retriever\", \"joiner\")\n",
        "rag_pipeline.connect(\"es_retriever\", \"joiner\")\n",
        "rag_pipeline.connect(\"joiner.documents\", \"prompt_builder.documents\")\n",
        "rag_pipeline.connect(\"prompt_builder\", \"llm\")\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "q1C5GHK_1Kkk"
      },
      "source": [
        "You can draw this pipeline and compare the architecture to the `indexing_pipeline` diagram we created earlier."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        },
        "id": "HAFTD5nt1L9a",
        "outputId": "90cbf82b-8fe5-439d-b099-08510e1c1098"
      },
      "outputs": [],
      "source": [
        "rag_pipeline.draw('rag_pipeline.png')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-Vr8MbGrEHZV"
      },
      "source": [
        "Try it out by asking a question."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 49,
          "referenced_widgets": [
            "8a6b993b2fbd4537a1f130adc08f2eb0",
            "cbe44862bf474ff692a359314a7c21f1",
            "04daef6e8b9e4779bbe41dc32f4e9083",
            "e5d659cdfd64477bbb9ce80aed7924f8",
            "d8777b76fb5341869afcb084e91231ee",
            "00a38829bf664b0084b5ec704047f00d",
            "f32af41f2b9543e497989b2c44e9d62d",
            "4ffb8a24b1a74cb8be55af79261e65ab",
            "28e5a76ec5b448c7b2d339913fb721c6",
            "d5d73be36bdb4ddb8fcd92f1ae7a2856",
            "f403167cb47840a3b0c796ae4c304401"
          ]
        },
        "id": "wj24fjXN0l6v",
        "outputId": "3c1eed33-c31c-4b72-bcda-fdd64744560b"
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Ranking by BM25...: 100%|██████████| 2/2 [00:00<00:00, 3134.76 docs/s]"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "\n"
          ]
        }
      ],
      "source": [
        "en_question = \"Is this apartment conveniently located?\"\n",
        "\n",
        "result = rag_pipeline.run({\n",
        "    \"router\": {\"text\": en_question},\n",
        "    \"prompt_builder\": {\"query\": en_question},\n",
        "})\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "i-2P5oqMeUmC",
        "outputId": "8151923f-bbb1-4e6a-fe4e-08c0d7cfcd49"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Yes, the apartment is conveniently located.\n"
          ]
        }
      ],
      "source": [
        "print(result[\"llm\"][\"replies\"][0])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "U4ChKAl1EKni"
      },
      "source": [
        "How does the pipeline perform en español?"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 49,
          "referenced_widgets": [
            "cb611c28471e487a8c53a7af8d0f7ae7",
            "c3876ec6082f466c89d14ea2dccd8207",
            "f4f835630d074a618f4389c69d1a75d2",
            "713bf7f3026f4a1daa52df12016caf82",
            "ae4725f43a3846acbdcbbf79f51166d0",
            "f0ff1b09bbc34065961a09ee894207bd",
            "d58eb54b8b04455b9e506598491b5b2b",
            "3115ad83af834fe4b4fa12362205d98c",
            "34c2218b0a4d4ba486530aeac007b00a",
            "dbdbd1d389d74c06acd9a1d3066c82dc",
            "7b62bd3498bb49ec9e1db68ca088e7ae"
          ]
        },
        "id": "B4_Be1bs1jxJ",
        "outputId": "0b96cf29-d633-4c9b-f54c-a785e1c2cbe4"
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Ranking by BM25...: 100%|██████████| 2/2 [00:00<00:00, 15887.52 docs/s]\n"
          ]
        }
      ],
      "source": [
        "es_question = \"¿El desayuno es genial?\"\n",
        "\n",
        "result = rag_pipeline.run({\n",
        "    \"router\": {\"text\": es_question},\n",
        "    \"prompt_builder\": {\"query\": es_question},\n",
        "})\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 26,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "w_1wibY61sjk",
        "outputId": "54f7506e-9af1-42b8-c0c9-cd13fb4cd9eb"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "No, el desayuno no es genial.\n"
          ]
        }
      ],
      "source": [
        "print(result[\"llm\"][\"replies\"][0])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IhHIJYjbTpAw"
      },
      "source": [
        "## What's next\n",
        "\n",
        "If you've been following along, now you know how to incorporate language detection into query and indexing Haystack piplines. Go forth and build the international application of your dreams. 🗺️\n",
        "\n",
        "\n",
        "If you liked this tutorial, there's more to learn about Haystack 2.0:\n",
        "- [Serializing Haystack Pipelines](https://haystack.deepset.ai/tutorials/29_serializing_pipelines)\n",
        "-  [Generating Structured Output with Loop-Based Auto-Correction](https://haystack.deepset.ai/tutorials/28_structured_output_with_loop)\n",
        "- [Preprocessing Different File Types](https://haystack.deepset.ai/tutorials/30_file_type_preprocessing_index_pipeline)\n",
        "\n",
        "To stay up to date on the latest Haystack developments, you can [sign up for our newsletter](https://landing.deepset.ai/haystack-community-updates?utm_campaign=developer-relations&utm_source=index_documents_based_on_language_tutorial)."
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "gpuType": "T4",
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.12.1"
    },
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "00a38829bf664b0084b5ec704047f00d": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "04daef6e8b9e4779bbe41dc32f4e9083": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "FloatProgressModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "FloatProgressModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "ProgressView",
            "bar_style": "success",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_4ffb8a24b1a74cb8be55af79261e65ab",
            "max": 2,
            "min": 0,
            "orientation": "horizontal",
            "style": "IPY_MODEL_28e5a76ec5b448c7b2d339913fb721c6",
            "value": 2
          }
        },
        "28e5a76ec5b448c7b2d339913fb721c6": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "ProgressStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "ProgressStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "bar_color": null,
            "description_width": ""
          }
        },
        "3115ad83af834fe4b4fa12362205d98c": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "34c2218b0a4d4ba486530aeac007b00a": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "ProgressStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "ProgressStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "bar_color": null,
            "description_width": ""
          }
        },
        "4ffb8a24b1a74cb8be55af79261e65ab": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "713bf7f3026f4a1daa52df12016caf82": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_dbdbd1d389d74c06acd9a1d3066c82dc",
            "placeholder": "​",
            "style": "IPY_MODEL_7b62bd3498bb49ec9e1db68ca088e7ae",
            "value": " 2/2 [00:00&lt;00:00, 108.06 docs/s]"
          }
        },
        "7b62bd3498bb49ec9e1db68ca088e7ae": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "8a6b993b2fbd4537a1f130adc08f2eb0": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HBoxModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HBoxModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HBoxView",
            "box_style": "",
            "children": [
              "IPY_MODEL_cbe44862bf474ff692a359314a7c21f1",
              "IPY_MODEL_04daef6e8b9e4779bbe41dc32f4e9083",
              "IPY_MODEL_e5d659cdfd64477bbb9ce80aed7924f8"
            ],
            "layout": "IPY_MODEL_d8777b76fb5341869afcb084e91231ee"
          }
        },
        "ae4725f43a3846acbdcbbf79f51166d0": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "c3876ec6082f466c89d14ea2dccd8207": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_f0ff1b09bbc34065961a09ee894207bd",
            "placeholder": "​",
            "style": "IPY_MODEL_d58eb54b8b04455b9e506598491b5b2b",
            "value": "Ranking by BM25...: 100%"
          }
        },
        "cb611c28471e487a8c53a7af8d0f7ae7": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HBoxModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HBoxModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HBoxView",
            "box_style": "",
            "children": [
              "IPY_MODEL_c3876ec6082f466c89d14ea2dccd8207",
              "IPY_MODEL_f4f835630d074a618f4389c69d1a75d2",
              "IPY_MODEL_713bf7f3026f4a1daa52df12016caf82"
            ],
            "layout": "IPY_MODEL_ae4725f43a3846acbdcbbf79f51166d0"
          }
        },
        "cbe44862bf474ff692a359314a7c21f1": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_00a38829bf664b0084b5ec704047f00d",
            "placeholder": "​",
            "style": "IPY_MODEL_f32af41f2b9543e497989b2c44e9d62d",
            "value": "Ranking by BM25...: 100%"
          }
        },
        "d58eb54b8b04455b9e506598491b5b2b": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "d5d73be36bdb4ddb8fcd92f1ae7a2856": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "d8777b76fb5341869afcb084e91231ee": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "dbdbd1d389d74c06acd9a1d3066c82dc": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "e5d659cdfd64477bbb9ce80aed7924f8": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_d5d73be36bdb4ddb8fcd92f1ae7a2856",
            "placeholder": "​",
            "style": "IPY_MODEL_f403167cb47840a3b0c796ae4c304401",
            "value": " 2/2 [00:00&lt;00:00, 74.12 docs/s]"
          }
        },
        "f0ff1b09bbc34065961a09ee894207bd": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "f32af41f2b9543e497989b2c44e9d62d": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "f403167cb47840a3b0c796ae4c304401": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "f4f835630d074a618f4389c69d1a75d2": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "FloatProgressModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "FloatProgressModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "ProgressView",
            "bar_style": "success",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_3115ad83af834fe4b4fa12362205d98c",
            "max": 2,
            "min": 0,
            "orientation": "horizontal",
            "style": "IPY_MODEL_34c2218b0a4d4ba486530aeac007b00a",
            "value": 2
          }
        }
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
